import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 *
 *@author Paul Ozog
 *
 * Implements a simple chat client using UDP.  
 *
 * The program has two parallel paths of execution:
 * 1. A thread (see run() method) that handles
 *    reading commands from the user's console and
 *    transmitting packets accordingly
 * 2. Listening for packets from the server and displaying
 *    the extracted messages using the ChatProtocol class
 *
 * See ChatProtocol for the structure of the packets, etc. 
 */
class ChatClient implements Runnable {
    public static String         serverName;
    public static InetAddress    serverIP;
    public static int            serverPort;
    public static DatagramSocket UDPSocket;
    public static byte[] buf = new byte[ChatProtocol.PACKETSIZE]; //256

    /**
     * @param args - hostname port
     * @return None
     *
     * Check args and call beginChat
     *
     * Catches exceptions for unknown host, and ports already
     * in use.  Acts accordingly
     *
     */
    public static void main(String[] args) {

	if (args.length != 2) {
	    printUsage();
	    System.exit(-1);
	} else {

	    serverName = args[0];
	    serverPort = Integer.parseInt(args[1]);

	    try {
	    	serverIP = InetAddress.getByName(serverName);
	    	UDPSocket = new DatagramSocket();
	    } catch (Exception e) {
	    	System.out.println(e);
		System.exit(1);
	    }

	    beginChat(args);
	} //end if

    } //end main

    /**
     * @param args - see args from main()
     * @return None
     * 
     * Calls the transmit thread (run()) and continues with 
     * receiving packets.  Extracts packet messages using
     * ChatProtocol. 
     *
     */
    public static void beginChat(String [] args) {

	//start reading from stdin and sending packets using 
	// a dedicated transmit thread... (see run())
	(new Thread(new ChatClient())).start();

	//...in the meantime, listen for packets received from server
	DatagramPacket RxPacket = new DatagramPacket(buf, buf.length);

	//this while loop will end when transmit thread ends. See run()
	while (true) {

	    //Don't exit main if a packet fails to arrive
	    try {
		UDPSocket.receive(RxPacket);
	    } catch (IOException e)  {
		System.out.println(e);
	    }
		    
	    System.out.println("");
	    System.out.println(ChatProtocol.extractMessage(RxPacket));
	    printPrompt();

	} // end while

    } // end beginChat

    /**
     * @param None
     * @return None
     *
     * Print the usage of ChatClient
     */
    public static void printUsage() {
	System.out.println("Usage: java ChatClient serverName serverPort");
    }

    /**
     * @param None
     * @return None
     *
     * Print the prompt according to spec.
     */
    public static void printPrompt() {
	System.out.print("] ");
    }

    /**
     * @param None
     * @return None
     * @implements Runnable
     *
     * This is the ChatClient's transmit thread
     *
     * Read commands from the user, checks their validity, and if 
     * everything's OK send a packet to server.
     *
     * When the user provides EOF (Ctrl-D), exit the java virtual machine
     */
    public void run() {
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	//Command is the line read from System.in
	String command; 

	System.out.println("Press Ctrl-D to quit");
	printPrompt();

	//Greet the server
	DatagramPacket GreetingPacket=
	    ChatProtocol.createGreetingPacket(serverIP,
					      serverPort);
	try {
	    UDPSocket.send(GreetingPacket);
	} catch (Exception e) {
	    System.out.println("Unable to greet server: " + e);
	    System.exit(-1);
	}

	try {
	    while ( (command = br.readLine()) != null) {

		//if there's bad input from the user, just print the
		// Exception for bad input, but don't exit program
		try {
		    handleCommand(command);
		} catch (Exception e) {
		    System.out.println(e);
		}

		printPrompt();

	    } //end while

	} catch (IOException e) {
	    //Do nothing
	}

	//User supplied EOF - exit VM
	System.exit(0);
	
    } //end run

    /**
     * @param command - String that is the user input (ie - "MESSAGE hello"
     * @return None
     *
     * Creates a packet representing command using the ChatProtocol class.
     * Sends the created packet. 
     */
    public static void handleCommand(String command) throws Exception {
	//Create a packet based on the ChatProtocol, and then send it
	DatagramPacket TxPacket = 
	    ChatProtocol.createMessagePacket(command,
					     serverIP,
					     serverPort);
	UDPSocket.send(TxPacket);
    } //end handleCommand

} //end ChatClient
